package com.chatplus.application.common.util;

import com.chatplus.application.common.exception.BadRequestException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import okhttp3.Authenticator;
import okhttp3.ConnectionPool;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import org.apache.commons.lang3.StringUtils;

import javax.net.ssl.*;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * OkHttpClient 公共类
 **/
public class OkHttpClientUtil {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(OkHttpClientUtil.class);
    private static final int READ_TIMEOUT = 500;

    private static final int CONNECT_TIMEOUT = 60;

    private static final int WRITE_TIMEOUT = 100;

    public static OkHttpClient getOkHttpClient(String proxyUrl, boolean verifySSL) {
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        OkHttpClient.Builder builder = new OkHttpClient
                .Builder();
        builder.addInterceptor(httpLoggingInterceptor);
        //读取超时
        builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
        //连接超时
        builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
        //写入超时
        builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
        //自定义连接池最大空闲连接数和等待时间大小，否则默认最大5个空闲连接
        builder.connectionPool(new ConnectionPool(32, 5, TimeUnit.MINUTES));
        if (StringUtils.isNotEmpty(proxyUrl)) {
            setProxy(builder, proxyUrl);
        }
        if (!verifySSL) {
            try {
                builder.sslSocketFactory(Objects.requireNonNull(sslSocketFactory()), x509TrustManager());
                builder.hostnameVerifier(getIgnoreSslHostnameVerifier());
            } catch (Exception e) {
                LOGGER.message("设置不验证SSL失败").exception(e);
            }
        }
        return builder.build();
    }

    private static void setProxy(OkHttpClient.Builder builder, String proxyUrl) {
        try {
            URI uri = new URI(proxyUrl);
            // 获取请求协议
            String protocol = uri.getScheme();
            String host = uri.getHost();
            if (StringUtils.isEmpty(protocol) || StringUtils.isEmpty(host)) {
                throw new BadRequestException("代理地址有误，当前代理地址【" + proxyUrl + "】，参考代理URL格式：" +
                        "【http://username:password@host:port、https://username:password@host:port、http://host:port、https://host:port】");
            }
            int port = uri.getPort();
            if (port == -1) { // 如果未指定端口，则使用默认端口
                port = protocol.equalsIgnoreCase("https") ? 443 : 80;
            }
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
            // 获取用户名和密码
            String userInfo = uri.getUserInfo();
            if (userInfo != null) {
                String[] parts = userInfo.split(":");
                String username = parts[0];
                String password = parts.length > 1 ? parts[1] : null;
                if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
                    // 如果设置了用户名密码
                    Authenticator proxyAuthenticator = (route, response) -> {
                        String credential = Credentials.basic("username", "password");
                        return response.request().newBuilder()
                                .header("Proxy-Authorization", credential)
                                .build();
                    };
                    builder.proxyAuthenticator(proxyAuthenticator);
                }
            }
            if ("https".equalsIgnoreCase(protocol)) {
                // 如果代理过程中ssl或tls相关的错误
                // 则需要加上sslSocketFactory(sslSocketFactory(), x509TrustManager())来处理证书验证
                // 这里默认的处理模式是全部放通，仅用于开发调测阶段
                builder.sslSocketFactory(Objects.requireNonNull(sslSocketFactory()), x509TrustManager());
            }
            builder.proxy(proxy);
        } catch (Exception e) {
            LOGGER.message("设置代理失败").exception(e);
        }
    }

    private static X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
                // 全部放通
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
                // 全部放通
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    private static SSLSocketFactory sslSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
        return sslContext.getSocketFactory();
    }

    public static HostnameVerifier getIgnoreSslHostnameVerifier() {
        return new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        };
    }

}
